use crate::{ApiError, ApiResult, ToError};
use chrono::{DateTime, Datelike, Local, NaiveDate, TimeDelta, TimeZone, Utc};
use core::fmt;

/// 字符串解析成日期
pub fn parse_local(date: &str) -> ApiResult<DateTime<Local>> {
    date.parse::<DateTime<Local>>()
        .to_err(|| ApiError::Biz("日期解析错误".into()))
}

/// 字符串解析成日期
pub fn parse_utc(date: &str) -> ApiResult<DateTime<Utc>> {
    date.parse::<DateTime<Utc>>()
        .to_err(|| ApiError::Biz("日期解析错误".into()))
}

/// 日期解析成字符串
pub fn format<Tz>(date_time: DateTime<Tz>, fmt: &str) -> String
where
    Tz: TimeZone,
    Tz::Offset: fmt::Display,
{
    date_time.format(fmt).to_string()
}

/// 获取某天的开始时间
pub fn begin_of_day<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    date_naive
        .and_hms_opt(0, 0, 0)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某天的结束时间
pub fn end_of_day<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    date_naive
        .and_hms_opt(23, 59, 59)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某月的开始时间
pub fn begin_of_month<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    let month = date_naive.month();
    NaiveDate::from_ymd_opt(year, month, 1)
        .unwrap()
        .and_hms_opt(0, 0, 0)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某月的结束时间
pub fn end_of_month<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    let month = date_naive.month();
    let days = days_in_month(year, month);
    NaiveDate::from_ymd_opt(year, month, days)
        .unwrap()
        .and_hms_opt(23, 59, 59)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某季度的开始时间
pub fn begin_of_quarter<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    let quarter = date_naive.quarter();
    let quarter_end_month = quarter * 3;
    let quarter_start_month = quarter_end_month - 2;
    NaiveDate::from_ymd_opt(year, quarter_start_month, 1)
        .unwrap()
        .and_hms_opt(0, 0, 0)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某季度的结束时间
pub fn end_of_quarter<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    let quarter = date_naive.quarter();
    let quarter_end_month = quarter * 3;
    let days = days_in_month(year, quarter_end_month);
    NaiveDate::from_ymd_opt(year, quarter_end_month, days)
        .unwrap()
        .and_hms_opt(23, 59, 59)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某年的开始时间
pub fn begin_of_year<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    NaiveDate::from_ymd_opt(year, 1, 1)
        .unwrap()
        .and_hms_opt(0, 0, 0)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某年的结束时间
pub fn end_of_year<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let year = date_naive.year();
    NaiveDate::from_ymd_opt(year, 12, 31)
        .unwrap()
        .and_hms_opt(23, 59, 59)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某周的开始时间
pub fn begin_of_week<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let weekday = date_naive.weekday();
    let days_from_monday = weekday.num_days_from_monday();
    let date_naive = date_naive - TimeDelta::days(days_from_monday as i64);
    date_naive
        .and_hms_opt(0, 0, 0)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某周的结束时间
pub fn end_of_week<Tz: TimeZone>(date_time: &DateTime<Tz>) -> DateTime<Tz> {
    let tz = date_time.timezone();
    let date_naive = date_time.date_naive();
    let weekday = date_naive.weekday();
    let days_from_monday = weekday.num_days_from_monday();
    let date_naive = date_naive - TimeDelta::days(days_from_monday as i64);
    let date_naive = date_naive + TimeDelta::days(6);
    date_naive
        .and_hms_opt(23, 59, 59)
        .unwrap()
        .and_local_timezone(tz)
        .unwrap()
}

/// 获取某年的某个月的天数
pub fn days_in_month(year: i32, month: u32) -> u32 {
    // 创建下个月的第一天，然后减去1天得到当前月的最后一天
    let next_month = if month == 12 {
        NaiveDate::from_ymd_opt(year + 1, 1, 1).unwrap()
    } else {
        NaiveDate::from_ymd_opt(year, month + 1, 1).unwrap()
    };

    let last_day_of_month = next_month - TimeDelta::days(1);
    last_day_of_month.day()
}
